﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="TraceHelper.cs" company="Collaboris Ltd.">
//   Copyright (c) Collaboris Ltd. All rights Reserved.
// </copyright>
// <summary>
//   Writes Trace output using the System.Diagnostics.Trace class. Trace will be directed to all of
//   the configured Trace listeners.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace Collaboris.Utils
{
    using System;
    using System.Diagnostics;
    using System.Xml.Serialization;

    /// <summary>
    /// Writes Trace output using the System.Diagnostics.Trace class. Trace will be directed to all of 
    /// the configured Trace listeners.
    /// </summary>
    [Serializable]
    public class TraceHelper
    {
        #region Fields

        private string ownerClassName = string.Empty;

        private TraceSwitch traceSwitch;

        #endregion

        #region Properties (1)

        [XmlIgnore]
        public TraceSwitch Switch
        {
            get
            {
                return this.traceSwitch;
            }            
        }

        #endregion Properties 

        #region Constructors

        public TraceHelper(object OwnerClass, TraceSwitch trcSwitch)
        {
            this.ownerClassName = OwnerClass.GetType().FullName;
            this.traceSwitch = trcSwitch;
        }

        public TraceHelper(string ownerClassName, TraceSwitch trcSwitch)
        {
            this.ownerClassName = ownerClassName;
            this.traceSwitch = trcSwitch;
        }
        
        #endregion constructors

        #region Methods (11)

        public void TraceError(string message, params object[] args)
        {
            WriteLineIf(this.traceSwitch.TraceError, TraceLevel.Error, this.ownerClassName, message, args);
        }

        public void TraceException(string methodName, Exception ex)
        {
            string msg = string.Format("Type '{0}' Message '{1}'", ex.GetType(), ex.Message);
            Trace.WriteLineIf(
                    this.traceSwitch.TraceError,
                    string.Format(
                            "{0} [EXCEPTION] - {1}:{2}(). {3}",
                            DateTime.Now.ToLongTimeString(),
                            this.ownerClassName,
                            methodName,
                            msg ));


            // Trace out the inners too now
            if (ex.InnerException != null)
                this.TraceException(methodName, ex.InnerException);
            else
            {
                Trace.WriteLineIf(this.traceSwitch.TraceError, 
                    string.Format(
                            "{0} [EXCEPTION] - {1}",
                            DateTime.Now.ToLongTimeString(),
                            ex.StackTrace));
            }
        }

        public void TraceInfo(string message, params object[] args)
        {
            WriteLineIf(this.traceSwitch.TraceInfo, TraceLevel.Info, string.Empty, message, args);
        }

        public void TraceMethodEnd(string methodName)
        {
            WriteLineIf(this.traceSwitch.TraceVerbose, TraceLevel.Verbose, this.ownerClassName, methodName, "Ending");
        }

        public void TraceMethodStart(string methodName)
        {
            WriteLineIf(this.traceSwitch.TraceVerbose, TraceLevel.Verbose, this.ownerClassName, methodName, "Starting");
        }

        public void TraceVerbose(string message, params object[] args)
        {
            WriteLineIf(this.traceSwitch.TraceVerbose, TraceLevel.Verbose, this.ownerClassName, message, args);
        }

        public void TraceWarning(string message, params object[] args)
        {
            WriteLineIf(this.traceSwitch.TraceWarning, TraceLevel.Warning, this.ownerClassName, message, args);
        }

        #endregion Methods 

        #region Static Methods

        public static void TraceException(TraceSwitch trcSwitch, string className, string methodName, Exception ex)
        {
            if (trcSwitch.TraceError)
                Trace.WriteLine(
                        string.Format("{0} [Exception] - {1}:{2}(). {3}",DateTime.Now.ToLongTimeString(),className,methodName,ex.Message));

            // Trace out the inners too now
            if (ex.InnerException != null)
                TraceException(trcSwitch, className, methodName, ex.InnerException);
            
        }

        public static void TraceInfo(TraceSwitch trcSwitch, string className, string message, params object[] args)
        {
            WriteLineIf(trcSwitch.TraceInfo, TraceLevel.Info, className, message, args);
        }

        public static void TraceMethodEnd(TraceSwitch trcSwitch, string className, string methodName)
        {
            WriteLineIf(trcSwitch.TraceVerbose, TraceLevel.Verbose, className, methodName, "Ending");
        }

        public static void TraceMethodStart(TraceSwitch trcSwitch, string className, string methodName)
        {
            WriteLineIf(trcSwitch.TraceVerbose, TraceLevel.Verbose, className, methodName, "Starting");
        }

        public static void TraceVerbose(TraceSwitch trcSwitch, string className, string message, params object[] args)
        {
            WriteLineIf(trcSwitch.TraceVerbose, TraceLevel.Verbose, className, message, args);
        }

        public static void TraceWarning(TraceSwitch trcSwitch, string className, string message, params object[] args)
        {
            WriteLineIf(trcSwitch.TraceWarning, TraceLevel.Warning, className, message, args);
        }

        public static void TraceError(TraceSwitch trcSwitch, string className, string message, params object[] args)
        {
            WriteLineIf(trcSwitch.TraceError, TraceLevel.Error, className, message, args);
        }

        /// <summary>
        /// write Trace output using System.Diagnostics.Trace.
        /// </summary>
        /// <param name="write">Condition to test before writing - pass Trace switch severity.</param>
        /// <param name="Level">Severity level.</param>
        /// <param name="Message">Message to write.</param>
        /// <param name="Args">Arguments to insert into message.</param>
        private static void WriteLineIf(bool write, TraceLevel Level, string ownerClassName, string Message, params object[] Args)
        {
            if (write)
            {
                if (Level != TraceLevel.Info)
                {
                    Trace.WriteLine(
                            string.Format(
                                    "{0} [{1}] - {2}. {3}",
                                    DateTime.Now.ToLongTimeString(),
                                    Level.ToString().ToUpper(),
                                    ownerClassName,
                                    string.Format(Message, Args)));
                }
                else
                {
                    Trace.WriteLine(string.Format("{0}", string.Format(Message, Args)));
                }
            }
        }

        /// <summary>
        /// write Trace output using System.Diagnostics.Trace.
        /// </summary>
        /// <param name="write">Condition to test before writing - pass Trace switch severity.</param>
        /// <param name="Level">Severity level.</param>
        /// <param name="message">Message to write.</param>
        /// <param name="Args">Arguments to insert into message.</param>
        private static void WriteLineIf(bool write, TraceLevel Level, string ownerClassName, string methodName, string message, params object[] Args)
        {
            if (write)
            {
                if (Level != TraceLevel.Info)
                {
                    Trace.WriteLine(
                            write,
                            string.Format(
                                    "{0} [{1}] - {2}:{3}(). {4}",
                                    DateTime.Now.ToLongTimeString(),
                                    Level.ToString().ToUpper(),
                                    ownerClassName,
                                    methodName,
                                    string.Format(message, Args)));
                }
                else
                {
                    Trace.WriteLine(
                     write,
                     string.Format(
                             "{0}",
                             string.Format(message, Args)));
             
                }
            }
        }

        #endregion
    }
}